import re
import uuid

import redis
from flask import request, g
from flask_restful import abort

from main.apis.api_constant import ADMIN, USER, VERIFY, PAY
from main.ext import cache
from main.models.admin.admin_model import AdminModel
from main.models.user.user_model import UsersModel


def generate_token(prefix):
    token = prefix + uuid.uuid4().hex
    return token


def generate_admin_token():
    return generate_token(ADMIN)


def generate_user_token():
    return generate_token(USER)


def generate_verify_token():
    return generate_token(VERIFY)


def generate_pay_token():
    return generate_token(PAY)


def get_user(model, arg):
    if not arg:
        return None
    # 如果传入的参数是id（int）
    if type(arg) == int:
        user = model.query.get(arg)
        if user:
            return user
    # 如果传入的参数是用户名（str）
    if type(arg) == str:
        user = model.query.filter(model.username == arg).first()
        if user:
            return user
    return None


def get_admin_user(arg):
    return get_user(AdminModel, arg)


def get_ordinary_user(arg):
    return get_user(UsersModel, arg)


def check_user_exits(arg):
    if not arg:
        abort(403, error='用户名或邮箱不能为空！')
    # 如果输入的是邮箱
    if '@' in arg:
        user = UsersModel.query.filter(UsersModel.email == arg).first()
    else:
        user = UsersModel.query.filter(UsersModel.username == arg).first()
    return user


def _verify():
    token = request.args.get('token')
    if not token:
        abort(401, error='未登录')
    if not token.startswith(ADMIN) and not token.startswith(USER):
        abort(403, error='非法操作！疑似攻击，请停止你的违规行为！')
    if not token.startswith(ADMIN):
        abort(401, error='已登录的用户可能不是管理员用户，或者您尚未登录。请登录管理员账户')
    user_id = cache.get(token)
    if not user_id:
        abort(401, error='此操作需要登录。如果您之前已登录，可能是登录过期，请重新登录。')
    user = get_admin_user(user_id)
    if not user:
        abort(401, error='您的账户状态异常，请联系管理员')
    # 如果登录，则将用户和token传到跨域全局变量g中，用于后面的权限认证
    g.user = user
    g.token = token


def login_required(func):
    def wrapper(*args, **kwargs):
        _verify()
        return func(*args, **kwargs)

    return wrapper


# 在login_required的基础上再进行权限判断，对一些需要指定权限的方法使用
def permission_required(permission: int):  # 装饰器的复杂化
    def permission_required_wrapper(func):
        def wrapper(*args, **kwargs):
            _verify()
            if not g.user.check_permission(permission):
                abort(403, error='权限不足')
            return func(*args, **kwargs)

        return wrapper

    return permission_required_wrapper


# 检查邮箱格式
def check_email(email: str):
    # 可使用字母、数字、下划线，少部分邮箱中间可能有点，需要以字母或数字开头，二级域名只能为字母或数字，顶级域名只能为字母
    pattern = re.compile(r'^[a-zA-Z0-9]+\.?\w+@[a-zA-Z0-9]+\.[a-zA-Z]+$')
    result = pattern.match(email)
    return result


def clear_other_login_caches(prefix: str, user_id: int, db: int = 0):
    """
    由于flask-caching模块未提供遍历所有缓存的方法，所以只能通过redis模块来看所有缓存
    取到所有缓存后，可以用redis也可以用flask-caching来取值，由于flask-caching提供了便捷的取值方法，所以采用flask-caching取值
    对取到的值进行判断，等于当前用户的id就删除，空的也删除
    :param prefix: 要清除缓存的用户的类别，值为 ADMIN 或 USER
    :param user_id: 要清除的用户的id
    :param db: 缓存所在的redis数据库id
    """
    r = redis.Redis('172.17.0.3', db=db)
    all_keys = r.keys()
    cache_prefix_len = len('cache:')
    keys = [key.decode('utf-8')[cache_prefix_len:] for key in all_keys if prefix in key.decode('utf-8')]
    for key in keys:
        value = cache.get(key)
        if value == user_id or not value:
            cache.delete(key)
